﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using IPC.Communication.Framework;
using IPC.Communication.Framework.BasicFramework;
using IPC.Communication.Framework.Core;
using IPC.Communication.Framework.Reflection;


namespace IPC.Communication.Framework.MQTT
{
    public class MqttHelper
    {
	    public static OperateResult<byte[]> CalculateLengthToMqttLength(int length)
	    {
		    if (length > 268435455)
		    {
			    return new OperateResult<byte[]>(StringResources.Language.MQTTDataTooLong);
		    }
		    if (length < 128)
		    {
			    return OperateResult.CreateSuccessResult(new byte[1]
			    {
				    (byte)length
			    });
		    }
		    if (length < 16384)
		    {
			    return OperateResult.CreateSuccessResult(new byte[2]
			    {
				    (byte)(length % 128 + 128),
				    (byte)(length / 128)
			    });
		    }
		    if (length < 2097152)
		    {
			    return OperateResult.CreateSuccessResult(new byte[3]
			    {
				    (byte)(length % 128 + 128),
				    (byte)(length / 128 % 128 + 128),
				    (byte)(length / 128 / 128)
			    });
		    }
		    return OperateResult.CreateSuccessResult(new byte[4]
		    {
			    (byte)(length % 128 + 128),
			    (byte)(length / 128 % 128 + 128),
			    (byte)(length / 128 / 128 % 128 + 128),
			    (byte)(length / 128 / 128 / 128)
		    });
	    }

	    public static OperateResult<byte[]> BuildMqttCommand(byte control, byte flags, byte[] variableHeader, byte[] payLoad)
	    {
		    control = (byte)(control << 4);
		    byte head = (byte)(control | flags);
		    return BuildMqttCommand(head, variableHeader, payLoad);
	    }

	    public static OperateResult<byte[]> BuildMqttCommand(byte head, byte[] variableHeader, byte[] payLoad)
	    {
		    if (variableHeader == null)
		    {
			    variableHeader = new byte[0];
		    }
		    if (payLoad == null)
		    {
			    payLoad = new byte[0];
		    }
		    OperateResult<byte[]> operateResult = CalculateLengthToMqttLength(variableHeader.Length + payLoad.Length);
		    if (!operateResult.IsSuccess)
		    {
			    return operateResult;
		    }
		    MemoryStream memoryStream = new MemoryStream();
		    memoryStream.WriteByte(head);
		    memoryStream.Write(operateResult.Content, 0, operateResult.Content.Length);
		    if (variableHeader.Length != 0)
		    {
			    memoryStream.Write(variableHeader, 0, variableHeader.Length);
		    }
		    if (payLoad.Length != 0)
		    {
			    memoryStream.Write(payLoad, 0, payLoad.Length);
		    }
		    return OperateResult.CreateSuccessResult(memoryStream.ToArray());
	    }

	    public static byte[] BuildSegCommandByString(string message)
	    {
		    byte[] array = string.IsNullOrEmpty(message) ? new byte[0] : Encoding.UTF8.GetBytes(message);
		    byte[] array2 = new byte[array.Length + 2];
		    array.CopyTo(array2, 2);
		    array2[0] = (byte)(array.Length / 256);
		    array2[1] = (byte)(array.Length % 256);
		    return array2;
	    }

	    public static string ExtraMsgFromBytes(byte[] buffer, ref int index)
	    {
		    int num = index;
		    int num2 = buffer[index] * 256 + buffer[index + 1];
		    index = index + 2 + num2;
		    return Encoding.UTF8.GetString(buffer, num + 2, num2);
	    }

	    public static string ExtraSubscribeMsgFromBytes(byte[] buffer, ref int index)
	    {
		    int num = index;
		    int num2 = buffer[index] * 256 + buffer[index + 1];
		    index = index + 3 + num2;
		    return Encoding.UTF8.GetString(buffer, num + 2, num2);
	    }

	    public static int ExtraIntFromBytes(byte[] buffer, ref int index)
	    {
		    int result = buffer[index] * 256 + buffer[index + 1];
		    index += 2;
		    return result;
	    }

	    public static byte[] BuildIntBytes(int data)
	    {
		    return new byte[2]
		    {
			    BitConverter.GetBytes(data)[1],
			    BitConverter.GetBytes(data)[0]
		    };
	    }

	    public static OperateResult<byte[]> BuildConnectMqttCommand(MqttConnectionOptions connectionOptions, string protocol = "MQTT")
	    {
		    List<byte> list = new List<byte>();
		    list.AddRange(new byte[2]
		    {
			    0,
			    4
		    });
		    list.AddRange(Encoding.ASCII.GetBytes(protocol));
		    list.Add(4);
		    byte b = 0;
		    if (connectionOptions.Credentials != null)
		    {
			    b = (byte)(b | 0x80);
			    b = (byte)(b | 0x40);
		    }
		    if (connectionOptions.CleanSession)
		    {
			    b = (byte)(b | 2);
		    }
		    list.Add(b);
		    if (connectionOptions.KeepAlivePeriod.TotalSeconds < 1.0)
		    {
			    connectionOptions.KeepAlivePeriod = TimeSpan.FromSeconds(1.0);
		    }
		    byte[] bytes = BitConverter.GetBytes((int)connectionOptions.KeepAlivePeriod.TotalSeconds);
		    list.Add(bytes[1]);
		    list.Add(bytes[0]);
		    List<byte> list2 = new List<byte>();
		    list2.AddRange(BuildSegCommandByString(connectionOptions.ClientId));
		    if (connectionOptions.Credentials != null)
		    {
			    list2.AddRange(BuildSegCommandByString(connectionOptions.Credentials.UserName));
			    list2.AddRange(BuildSegCommandByString(connectionOptions.Credentials.Password));
		    }
		    return BuildMqttCommand(1, 0, list.ToArray(), list2.ToArray());
	    }

	    public static OperateResult CheckConnectBack(byte code, byte[] data)
	    {
		    if (code >> 4 != 2)
		    {
			    return new OperateResult("MQTT Connection Back Is Wrong: " + code.ToString());
		    }
		    if (data.Length < 2)
		    {
			    return new OperateResult("MQTT Connection Data Is Short: " + SoftBasic.ByteToHexString(data, ' '));
		    }
		    int num = data[1];
		    int num2 = data[0];
		    if (num > 0)
		    {
			    return new OperateResult(num, GetMqttCodeText(num));
		    }
		    return OperateResult.CreateSuccessResult();
	    }

	    public static string GetMqttCodeText(int status)
	    {
		    switch (status)
		    {
		    case 1:
			    return StringResources.Language.MQTTStatus01;
		    case 2:
			    return StringResources.Language.MQTTStatus02;
		    case 3:
			    return StringResources.Language.MQTTStatus03;
		    case 4:
			    return StringResources.Language.MQTTStatus04;
		    case 5:
			    return StringResources.Language.MQTTStatus05;
		    default:
			    return StringResources.Language.UnknownError;
		    }
	    }

	    public static OperateResult<byte[]> BuildPublishMqttCommand(MqttPublishMessage message)
	    {
		    byte b = 0;
		    if (!message.IsSendFirstTime)
		    {
			    b = (byte)(b | 8);
		    }
		    if (message.Message.Retain)
		    {
			    b = (byte)(b | 1);
		    }
		    if (message.Message.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
		    {
			    b = (byte)(b | 2);
		    }
		    else if (message.Message.QualityOfServiceLevel == MqttQualityOfServiceLevel.ExactlyOnce)
		    {
			    b = (byte)(b | 4);
		    }
		    else if (message.Message.QualityOfServiceLevel == MqttQualityOfServiceLevel.OnlyTransfer)
		    {
			    b = (byte)(b | 6);
		    }
		    List<byte> list = new List<byte>();
		    list.AddRange(BuildSegCommandByString(message.Message.Topic));
		    if (message.Message.QualityOfServiceLevel != 0)
		    {
			    list.Add(BitConverter.GetBytes(message.Identifier)[1]);
			    list.Add(BitConverter.GetBytes(message.Identifier)[0]);
		    }
		    return BuildMqttCommand(3, b, list.ToArray(), message.Message.Payload);
	    }

	    public static OperateResult<byte[]> BuildPublishMqttCommand(string topic, byte[] payload)
	    {
		    return BuildMqttCommand(3, 0, BuildSegCommandByString(topic), payload);
	    }

	    public static OperateResult<byte[]> BuildSubscribeMqttCommand(MqttSubscribeMessage message)
	    {
		    List<byte> list = new List<byte>();
		    List<byte> list2 = new List<byte>();
		    list.Add(BitConverter.GetBytes(message.Identifier)[1]);
		    list.Add(BitConverter.GetBytes(message.Identifier)[0]);
		    for (int i = 0; i < message.Topics.Length; i++)
		    {
			    list2.AddRange(BuildSegCommandByString(message.Topics[i]));
			    if (message.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtMostOnce)
			    {
				    list2.AddRange(new byte[1]);
			    }
			    else if (message.QualityOfServiceLevel == MqttQualityOfServiceLevel.AtLeastOnce)
			    {
				    list2.AddRange(new byte[1]
				    {
					    1
				    });
			    }
			    else
			    {
				    list2.AddRange(new byte[1]
				    {
					    2
				    });
			    }
		    }
		    return BuildMqttCommand(8, 2, list.ToArray(), list2.ToArray());
	    }

	    public static OperateResult<byte[]> BuildUnSubscribeMqttCommand(MqttSubscribeMessage message)
	    {
		    List<byte> list = new List<byte>();
		    List<byte> list2 = new List<byte>();
		    list.Add(BitConverter.GetBytes(message.Identifier)[1]);
		    list.Add(BitConverter.GetBytes(message.Identifier)[0]);
		    for (int i = 0; i < message.Topics.Length; i++)
		    {
			    list2.AddRange(BuildSegCommandByString(message.Topics[i]));
		    }
		    return BuildMqttCommand(10, 2, list.ToArray(), list2.ToArray());
	    }

	    public static OperateResult<string, byte[]> ExtraMqttReceiveData(byte mqttCode, byte[] data)
	    {
		    if (data.Length < 2)
		    {
			    return new OperateResult<string, byte[]>(StringResources.Language.ReceiveDataLengthTooShort + data.Length.ToString());
		    }
		    int num = data[0] * 256 + data[1];
		    if (data.Length < 2 + num)
		    {
			    return new OperateResult<string, byte[]>(String.Format("Code[{0:X2}] ExtraMqttReceiveData Error: {1}", mqttCode, SoftBasic.ByteToHexString(data, ' ')));
		    }
		    string value = (num > 0) ? Encoding.UTF8.GetString(data, 2, num) : string.Empty;
		    byte[] array = new byte[data.Length - num - 2];
		    Array.Copy(data, num + 2, array, 0, array.Length);
		    return OperateResult.CreateSuccessResult(value, array);
	    }

        //[AsyncStateMachine(typeof(<HandleObjectMethod>d__16))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult<string>> HandleObjectMethod(MqttSession mqttSession, MqttClientApplicationMessage message, object obj)
        //{
        //    <HandleObjectMethod>d__16 stateMachine = new <HandleObjectMethod>d__16();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<string>>.Create();
        //    stateMachine.mqttSession = mqttSession;
        //    stateMachine.message = message;
        //    stateMachine.obj = obj;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<HandleObjectMethod>d__17))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult<string>> HandleObjectMethod(MqttSession mqttSession, MqttClientApplicationMessage message, MqttRpcApiInfo apiInformation)
        //{
        //    <HandleObjectMethod>d__17 stateMachine = new <HandleObjectMethod>d__17();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<string>>.Create();
        //    stateMachine.mqttSession = mqttSession;
        //    stateMachine.message = message;
        //    stateMachine.apiInformation = apiInformation;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

	    public static List<MqttRpcApiInfo> GetSyncServicesApiInformationFromObject(object obj)
	    {
		    Type type = obj as Type;
		    if ((object)type != null)
		    {
			    return GetSyncServicesApiInformationFromObject(type.Name, type);
		    }
		    return GetSyncServicesApiInformationFromObject(obj.GetType().Name, obj);
	    }

	    public static List<MqttRpcApiInfo> GetSyncServicesApiInformationFromObject(string api, object obj, HslMqttPermissionAttribute permissionAttribute = null)
	    {
		    Type type = null;
		    Type type2 = obj as Type;
		    if ((object)type2 != null)
		    {
			    type = type2;
			    obj = null;
		    }
		    else
		    {
			    type = obj.GetType();
		    }
		    MethodInfo[] methods = type.GetMethods();
		    List<MqttRpcApiInfo> list = new List<MqttRpcApiInfo>();
		    MethodInfo[] array = methods;
		    foreach (MethodInfo method in array)
		    {
			    OperateResult<MqttRpcApiInfo> mqttSyncServicesApiFromMethod = GetMqttSyncServicesApiFromMethod(api, method, obj, permissionAttribute);
			    if (mqttSyncServicesApiFromMethod.IsSuccess)
			    {
				    list.Add(mqttSyncServicesApiFromMethod.Content);
			    }
		    }
		    PropertyInfo[] properties = type.GetProperties();
		    PropertyInfo[] array2 = properties;
		    foreach (PropertyInfo propertyInfo in array2)
		    {
			    OperateResult<HslMqttApiAttribute, MqttRpcApiInfo> mqttSyncServicesApiFromProperty = GetMqttSyncServicesApiFromProperty(api, propertyInfo, obj, permissionAttribute);
			    if (mqttSyncServicesApiFromProperty.IsSuccess)
			    {
				    if (!mqttSyncServicesApiFromProperty.Content1.PropertyUnfold)
				    {
					    list.Add(mqttSyncServicesApiFromProperty.Content2);
				    }
				    else if (propertyInfo.GetValue(obj, null) != null)
				    {
					    List<MqttRpcApiInfo> syncServicesApiInformationFromObject = GetSyncServicesApiInformationFromObject(mqttSyncServicesApiFromProperty.Content2.ApiTopic, propertyInfo.GetValue(obj, null), permissionAttribute);
					    list.AddRange(syncServicesApiInformationFromObject);
				    }
			    }
		    }
		    return list;
	    }

	    private static string GetReturnTypeDescription(Type returnType)
	    {
		    if (returnType.IsSubclassOf(typeof(OperateResult)))
		    {
			    if (returnType == typeof(OperateResult))
			    {
				    return returnType.Name;
			    }
			    if (returnType.GetProperty("Content") != null)
			    {
				    return "OperateResult<" + returnType.GetProperty("Content").PropertyType.Name + ">";
			    }
			    StringBuilder stringBuilder = new StringBuilder("OperateResult<");
			    for (int i = 1; i <= 10; i++)
			    {
				    if (!(returnType.GetProperty("Content" + i.ToString()) != null))
				    {
					    break;
				    }
				    if (i != 1)
				    {
					    stringBuilder.Append(",");
				    }
				    stringBuilder.Append(returnType.GetProperty("Content" + i.ToString()).PropertyType.Name);
			    }
			    stringBuilder.Append(">");
			    return stringBuilder.ToString();
		    }
		    return returnType.Name;
	    }

	    public static OperateResult<MqttRpcApiInfo> GetMqttSyncServicesApiFromMethod(string api, MethodInfo method, object obj, HslMqttPermissionAttribute permissionAttribute = null)
	    {
		    object[] customAttributes = method.GetCustomAttributes(typeof(HslMqttApiAttribute), inherit: false);
		    if (customAttributes == null || customAttributes.Length == 0)
		    {
			    return new OperateResult<MqttRpcApiInfo>(String.Format("Current Api ：[{0}] not support Api attribute", method));
		    }
		    HslMqttApiAttribute hslMqttApiAttribute = (HslMqttApiAttribute)customAttributes[0];
		    MqttRpcApiInfo mqttRpcApiInfo = new MqttRpcApiInfo();
		    mqttRpcApiInfo.SourceObject = obj;
		    mqttRpcApiInfo.Method = method;
		    mqttRpcApiInfo.Description = hslMqttApiAttribute.Description;
		    mqttRpcApiInfo.HttpMethod = hslMqttApiAttribute.HttpMethod.ToUpper();
		    if (string.IsNullOrEmpty(hslMqttApiAttribute.ApiTopic))
		    {
			    hslMqttApiAttribute.ApiTopic = method.Name;
		    }
		    if (permissionAttribute == null)
		    {
			    customAttributes = method.GetCustomAttributes(typeof(HslMqttPermissionAttribute), inherit: false);
			    if (customAttributes != null && customAttributes.Length != 0)
			    {
				    mqttRpcApiInfo.PermissionAttribute = (HslMqttPermissionAttribute)customAttributes[0];
			    }
		    }
		    else
		    {
			    mqttRpcApiInfo.PermissionAttribute = permissionAttribute;
		    }
		    if (string.IsNullOrEmpty(api))
		    {
			    mqttRpcApiInfo.ApiTopic = hslMqttApiAttribute.ApiTopic;
		    }
		    else
		    {
			    mqttRpcApiInfo.ApiTopic = api + "/" + hslMqttApiAttribute.ApiTopic;
		    }
		    ParameterInfo[] parameters = method.GetParameters();
		    StringBuilder stringBuilder = new StringBuilder();
		    if (method.ReturnType.IsSubclassOf(typeof(Task)))
		    {
			    stringBuilder.Append("Task<" + GetReturnTypeDescription(method.ReturnType.GetProperty("Result").PropertyType) + ">");
		    }
		    else
		    {
			    stringBuilder.Append(GetReturnTypeDescription(method.ReturnType));
		    }
		    stringBuilder.Append(" ");
		    stringBuilder.Append(mqttRpcApiInfo.ApiTopic);
		    stringBuilder.Append("(");
		    for (int i = 0; i < parameters.Length; i++)
		    {
			    if (parameters[i].ParameterType != typeof(ISessionContext))
			    {
				    stringBuilder.Append(parameters[i].ParameterType.Name);
				    stringBuilder.Append(" ");
				    stringBuilder.Append(parameters[i].Name);
				    if (i != parameters.Length - 1)
				    {
					    stringBuilder.Append(",");
				    }
			    }
		    }
		    stringBuilder.Append(")");
		    mqttRpcApiInfo.MethodSignature = stringBuilder.ToString();
		    mqttRpcApiInfo.ExamplePayload = ((object)HslReflectionHelper.GetParametersFromJson(method, parameters)).ToString();
		    return OperateResult.CreateSuccessResult(mqttRpcApiInfo);
	    }

	    public static OperateResult<HslMqttApiAttribute, MqttRpcApiInfo> GetMqttSyncServicesApiFromProperty(string api, PropertyInfo property, object obj, HslMqttPermissionAttribute permissionAttribute = null)
	    {
		    object[] customAttributes = property.GetCustomAttributes(typeof(HslMqttApiAttribute), inherit: false);
		    if (customAttributes == null || customAttributes.Length == 0)
		    {
                return new OperateResult<HslMqttApiAttribute, MqttRpcApiInfo>(String.Format("Current Api ：[{0}] not support Api attribute", property));
		    }
		    HslMqttApiAttribute hslMqttApiAttribute = (HslMqttApiAttribute)customAttributes[0];
		    MqttRpcApiInfo mqttRpcApiInfo = new MqttRpcApiInfo();
		    mqttRpcApiInfo.SourceObject = obj;
		    mqttRpcApiInfo.Property = property;
		    mqttRpcApiInfo.Description = hslMqttApiAttribute.Description;
		    mqttRpcApiInfo.HttpMethod = hslMqttApiAttribute.HttpMethod.ToUpper();
		    if (string.IsNullOrEmpty(hslMqttApiAttribute.ApiTopic))
		    {
			    hslMqttApiAttribute.ApiTopic = property.Name;
		    }
		    if (permissionAttribute == null)
		    {
			    customAttributes = property.GetCustomAttributes(typeof(HslMqttPermissionAttribute), inherit: false);
			    if (customAttributes != null && customAttributes.Length != 0)
			    {
				    mqttRpcApiInfo.PermissionAttribute = (HslMqttPermissionAttribute)customAttributes[0];
			    }
		    }
		    else
		    {
			    mqttRpcApiInfo.PermissionAttribute = permissionAttribute;
		    }
		    if (string.IsNullOrEmpty(api))
		    {
			    mqttRpcApiInfo.ApiTopic = hslMqttApiAttribute.ApiTopic;
		    }
		    else
		    {
			    mqttRpcApiInfo.ApiTopic = api + "/" + hslMqttApiAttribute.ApiTopic;
		    }
		    StringBuilder stringBuilder = new StringBuilder();
		    stringBuilder.Append(GetReturnTypeDescription(property.PropertyType));
		    stringBuilder.Append(" ");
		    stringBuilder.Append(mqttRpcApiInfo.ApiTopic);
		    stringBuilder.Append(" { ");
		    if (property.CanRead)
		    {
			    stringBuilder.Append("get; ");
		    }
		    if (property.CanWrite)
		    {
			    stringBuilder.Append("set; ");
		    }
		    stringBuilder.Append("}");
		    mqttRpcApiInfo.MethodSignature = stringBuilder.ToString();
		    mqttRpcApiInfo.ExamplePayload = string.Empty;
		    return OperateResult.CreateSuccessResult(hslMqttApiAttribute, mqttRpcApiInfo);
	    }
    }
}
